﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Data.Sql;

namespace RecipeBookBusiness
{
    public class Recipe
    {
        #region Inner Classes
        private partial class RecipeIngredient
        {
            public Ingredient _ingredient;
            public string _amount;

            public RecipeIngredient(Ingredient i, string amount)
            {
                _ingredient = i;
                _amount = amount;
            }

        }
        #endregion

        private RecipeBookEntities _entities = new RecipeBookEntities();
        private int _recipeID;
        private string _name;
        private int _servingSize;
        private int _userAddedID;
        private string _nutritionalInfo;
        private string _instructions;
        private DateTime _dateAdded;
        private List<RecipeIngredient> _ingredients;
        private List<int> _equipmentIDs;
        private List<int> _categoriesIDs;

        #region Constructors
        public Recipe(int recipeID)
        {
            loadRecipeClass(recipeID);
        }

        public Recipe(string name, int servingSize, int userAddedID, string nutritionalInfo, string instructions, DateTime dateAdded)
        {
            try
            {
                RecipeDataRow rdr = new RecipeDataRow();
                rdr.Name = name;
                rdr.ServingSize = servingSize;
                rdr.UserAddedID = userAddedID;
                rdr.NutritionalInfo = nutritionalInfo;
                rdr.Instructions = instructions;
                rdr.DateAdded = dateAdded;

                //Save to DB and get ID
                _entities.AddToRecipeDataRowSet(rdr);
                _entities.SaveChanges();
                int newRecipeID = 0;
                foreach (RecipeDataRow idRdr in _entities.RecipeDataRowSet)
                {
                    if (idRdr.ID > newRecipeID)
                        newRecipeID = idRdr.ID;
                }
                loadRecipeClass(newRecipeID);
            }
            catch (Exception ex)
            {
                //TODO: Real exception handling
                Console.Write(ex.Message);
            }
        }
        #endregion

        #region Recipe methods
        private void loadRecipeClass(int recipeID)
        {
            RecipeDataRow recipeDR = (from c in _entities.RecipeDataRowSet
                                      where c.ID == recipeID
                                      select c).FirstOrDefault();
            _recipeID = recipeDR.ID;
            _name = recipeDR.Name;
            _servingSize = recipeDR.ServingSize;
            _userAddedID = recipeDR.UserAddedID;
            _nutritionalInfo = recipeDR.NutritionalInfo;
            _instructions = recipeDR.Instructions;
            _dateAdded = recipeDR.DateAdded;
            
            _ingredients = new List<RecipeIngredient>();
            foreach (RecipeIngredientDataRow ridr in _entities.RecipeIngredientDataRowSet)
            {
                if (ridr.IDRecipe == _recipeID)
                {
                    _ingredients.Add(new RecipeIngredient((new Ingredient(ridr.IDIngredient)), ridr.Amount));
                }
            }

            _equipmentIDs = new List<int>();
            foreach (RecipeEquipmentDataRow redr in _entities.RecipeEquipmentDataRowSet)
            {
                if (redr.IDRecipe == _recipeID)
                {
                    _equipmentIDs.Add(redr.IDEquipment);
                }
            }

            _categoriesIDs = new List<int>();
            foreach (RecipeCategoryDataRow rcdr in _entities.RecipeCategoryDataRowSet)
            {
                if (rcdr.IDRecipe == _recipeID)
                {
                    _categoriesIDs.Add(rcdr.IDCategory);
                }
            }
        }

        public void UpdateRecipe(string name, int servingSize, string nutritionalInfo, string instructions)
        {
            RecipeDataRow recipeDR = (from c in _entities.RecipeDataRowSet
                                      where c.ID == _recipeID
                                      select c).FirstOrDefault();
            bool needToUpdate = false;
            if (!_name.Equals(name))
            {
                _name = name;
                needToUpdate = true;
            }
            if (!_servingSize.Equals(servingSize))
            {
                _servingSize = servingSize;
                needToUpdate = true;
            }
            if (!_nutritionalInfo.Equals(nutritionalInfo))
            {
                _nutritionalInfo = nutritionalInfo;
                needToUpdate = true;
            }
            if (!_instructions.Equals(instructions))
            {
                _instructions = instructions;
                needToUpdate = true;
            }

            if (needToUpdate)
            {
                recipeDR.Name = _name;
                recipeDR.ServingSize = _servingSize;
                recipeDR.NutritionalInfo = _nutritionalInfo;
                recipeDR.Instructions = _instructions;
                _entities.SaveChanges();
            }
        }
        #endregion

        #region Equipment methods
        public void AddEquipment(int equipmentID)
        {
            try
            {
                RecipeEquipmentDataRow redr = new RecipeEquipmentDataRow();
                redr.IDEquipment = equipmentID;
                redr.IDRecipe = _recipeID;
                _entities.AddToRecipeEquipmentDataRowSet(redr);
                _entities.SaveChanges();

                _equipmentIDs.Add(equipmentID);
            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }

        public void RemoveEquipment(int equipmentID)
        {
            try
            {
                int indexToRemove = -1;
                foreach (int eID in _equipmentIDs)
                {
                    if (eID == equipmentID)
                    {
                        indexToRemove = _equipmentIDs.IndexOf(eID);
                    }
                }

                if (indexToRemove == -1)
                    return; //error - equipment not found

                //Remove using SQL
                IQueryable<RecipeEquipmentDataRow> reQuery =
                    from re in _entities.RecipeEquipmentDataRowSet
                    where re.IDRecipe == _recipeID
                    where re.IDEquipment == equipmentID
                    select re;
                List<RecipeEquipmentDataRow> selectedRe = reQuery.ToList();
                if (selectedRe != null && selectedRe.Count > 0)
                {
                    RecipeEquipmentDataRow reToDelete = selectedRe.First();
                    _entities.DeleteObject(reToDelete);
                    _entities.SaveChanges();
                }
                else
                {
                    return; //error - recipe-ingredient not found
                }


                //Remove from object
                _equipmentIDs.RemoveAt(indexToRemove);
            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }
        #endregion

        #region Category methods
        public void AddCategory(int catID)
        {
            try
            {
                RecipeCategoryDataRow rcdr = new RecipeCategoryDataRow();
                rcdr.IDCategory = catID;
                rcdr.IDRecipe = _recipeID;
                _entities.AddToRecipeCategoryDataRowSet(rcdr);
                _entities.SaveChanges();

                _categoriesIDs.Add(catID);
            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }

        public void RemoveCategory(int catID)
        {
            try
            {
                int indexToRemove = -1;
                foreach (int cID in _categoriesIDs)
                {
                    if (cID == catID)
                    {
                        indexToRemove = _categoriesIDs.IndexOf(cID);
                    }
                }

                if (indexToRemove == -1)
                    return; //error - category not found

                //Remove using SQL
                IQueryable<RecipeCategoryDataRow> rcQuery =
                    from rc in _entities.RecipeCategoryDataRowSet
                    where rc.IDRecipe == _recipeID
                    where rc.IDCategory == catID
                    select rc;
                List<RecipeCategoryDataRow> selectedRc = rcQuery.ToList();
                if (selectedRc != null && selectedRc.Count > 0)
                {
                    RecipeCategoryDataRow rcToDelete = selectedRc.First();
                    _entities.DeleteObject(rcToDelete);
                    _entities.SaveChanges();
                }
                else
                {
                    return; //error - recipe-category not found
                }


                //Remove from object
                _categoriesIDs.RemoveAt(indexToRemove);
            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }
        #endregion

        #region RecipeIngredient methods
        public void AddIngredient(Ingredient ingred, string amount)
        {
            try
            {
                //Add using SQL
                RecipeIngredientDataRow ridr = new RecipeIngredientDataRow();
                ridr.IDIngredient = ingred.ID;
                ridr.IDRecipe = _recipeID;
                ridr.Amount = amount;
                _entities.AddToRecipeIngredientDataRowSet(ridr);
                _entities.SaveChanges();

                //Add to object
                _ingredients.Add(new RecipeIngredient(ingred, amount));

            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }

        public void RemoveIngredient(Ingredient ingredToRemove)
        {
            try
            {
                int indexToRemove = -1;
                foreach (RecipeIngredient ri in _ingredients)
                {
                    if (ri._ingredient.ID == ingredToRemove.ID)
                    {
                        indexToRemove = _ingredients.IndexOf(ri);
                    }
                }

                if (indexToRemove == -1)
                    return; //error - ingredient not found

                //Remove using SQL
                IQueryable<RecipeIngredientDataRow> riQuery = 
                    from ri in _entities.RecipeIngredientDataRowSet
                    where ri.IDRecipe == _recipeID
                    where ri.IDIngredient == ingredToRemove.ID
                    select ri;
                List<RecipeIngredientDataRow> selectedRi = riQuery.ToList();
                if (selectedRi != null && selectedRi.Count > 0)
                {
                    RecipeIngredientDataRow riToDelete = selectedRi.First();
                    _entities.DeleteObject(riToDelete);
                    _entities.SaveChanges();
                }
                else
                {
                    return; //error - recipe-ingredient not found
                }


                //Remove from object
                _ingredients.RemoveAt(indexToRemove);
            }
            catch(Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }

        public void UpdateIngredient(Ingredient ingred, string newAmount)
        {
            try
            {
                int indexToUpdare = -1;
                foreach (RecipeIngredient ri in _ingredients)
                {
                    if (ri._ingredient.ID == ingred.ID)
                    {
                        indexToUpdare = _ingredients.IndexOf(ri);
                    }
                }

                if (indexToUpdare == -1)
                    return; //error - ingredient not found

                //Update using SQL
                IQueryable<RecipeIngredientDataRow> riQuery =
                    from ri in _entities.RecipeIngredientDataRowSet
                    where ri.IDRecipe == _recipeID
                    where ri.IDIngredient == ingred.ID
                    select ri;
                List<RecipeIngredientDataRow> selectedRi = riQuery.ToList();
                if (selectedRi != null && selectedRi.Count > 0)
                {
                    RecipeIngredientDataRow riToUpdate = selectedRi.First();
                    riToUpdate.Amount = newAmount;
                    _entities.SaveChanges();
                }
                else
                {
                    return; //error - recipe-ingredient not found
                }


                //Remove from object
                _ingredients[indexToUpdare]._amount = newAmount;
            }
            catch (Exception ex)
            {
                //TODO: Return real error
                Console.Write(ex.Message);
            }
        }
        #endregion

        #region Properties
        public int RecipeID
        {
            get
            {
                return _recipeID;
            }
        }

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public int ServingSize
        {
            get
            {
                return _servingSize;
            }
        }

        public int UserAddedID
        {
            get
            {
                return _userAddedID;
            }
        }

        public string NutritionalInfo
        {
            get
            {
                return _nutritionalInfo;
            }
        }

        public string Instructions
        {
            get
            {
                return _instructions;
            }
        }

        public DateTime DateAdded
        {
            get
            {
                return _dateAdded;
            }
        }

        public List<KeyValuePair<Ingredient, string>> Ingredients
        {
            get
            {
                List<KeyValuePair<Ingredient, string>> ingredientList = new List<KeyValuePair<Ingredient, string>>();
                foreach (RecipeIngredient ri in _ingredients)
                {
                    ingredientList.Add(new KeyValuePair<Ingredient, string>(ri._ingredient, ri._amount));
                }
                return ingredientList;
            }
        }

        public List<int> IngredientsByID
        {
            get
            {
                List<int> ingredientList = new List<int>();
                foreach (RecipeIngredient ri in _ingredients)
                {
                    ingredientList.Add(ri._ingredient.ID);
                }
                return ingredientList;
            }
        }

        public List<int> Equipment
        {
            get
            {
                return _equipmentIDs;
            }
        }

        public List<int> Categories
        {
            get
            {
                return _categoriesIDs;
            }
        }
        #endregion
    }
}
